#include "unity.h"
#include "mock_bsp_test_commom.h" // CMock 生成的 mock 头文件
#include "Rt_LUT_Config.h"

// Test instances
XRt1553B testInstance;
XRt1553B_MsgBlkDesc testCmdInfo;

void setUp(void)
{
    // Initialize test structures before each test
    memset(&testInstance, 0, sizeof(testInstance));
    memset(&testCmdInfo, 0, sizeof(testCmdInfo));
    testInstance.BaseAddress = 0x1000;
    testInstance.CMDStack_ReadPtr = 0x00;
}

void tearDown(void)
{
    // Cleanup after each test (if needed)
}

// Test case 1: Device is busy processing a message
void test_XRt1553B_GetCMDInfo_WhenDeviceIsBusy_ShouldReturnZero(void)
{
    // Arrange
    u32 cfg1_value = XRT53_CFG1_MSG_BUSY;
    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(0, result);
}

// Test case 2: No new message (read and write pointers are equal)
void test_XRt1553B_GetCMDInfo_WhenNoNewMessage_ShouldReturnZero(void)
{
    // Arrange
    u32 cfg1_value = 0;        // Not busy
    u32 stack_writePtr = 0x10; // Same as read pointer
    testInstance.CMDStack_ReadPtr = 0x10;

    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, XRT53_STACKA_PTR_OFFSET, stack_writePtr);

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(0, result);
}

// Test case 3: Message start marker present
void test_XRt1553B_GetCMDInfo_WhenSOMMarkerPresent_ShouldReturnZero(void)
{
    // Arrange
    u32 cfg1_value = 0;        // Not busy
    u32 stack_writePtr = 0x20; // Different from read pointer
    testInstance.CMDStack_ReadPtr = 0x10;

    u32 blockStatusWord = XRT53_BLOCK_STATWORDS_SOM_MASK; // Contains SOM marker

    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, XRT53_STACKA_PTR_OFFSET, stack_writePtr);

    // 读消息指针
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, testInstance.CMDStack_ReadPtr, 0x4000); // BlockStatusWord
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, testInstance.CMDStack_ReadPtr + 1, 0);  // TimeTag
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, testInstance.CMDStack_ReadPtr + 2, 0);  // DataBlkPtr_or_ModeWord
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, testInstance.CMDStack_ReadPtr + 3, 0);  // CMDWord

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(0, result);
}

// Test case 4: Successful message read without wrap
void test_XRt1553B_GetCMDInfo_WhenMessageAvailableNoWrap_ShouldReturnMessageCount(void)
{
    // Arrange
    u32 cfg1_value = 0;        // Not busy
    u32 stack_writePtr = 0x20; // Write pointer ahead of read pointer
    testInstance.CMDStack_ReadPtr = 0x10;

    u32 blockStatusWord = 0x50000000; // No SOM, with BUSA=1, rollover=0, error=0
    u32 timeTag = 0x12345678;
    u32 dataBlkPtr = 0xABCDEF00;
    u32 cmdWord = 0x87654321; // RTaddr=0x10, T/R=1, SubAddr=0x19, DataLen=0x01

    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, XRT53_STACKA_PTR_OFFSET, stack_writePtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x10, blockStatusWord);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x11, timeTag);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x12, dataBlkPtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x13, cmdWord);

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(blockStatusWord, testCmdInfo.BlockStatusWord);
    TEST_ASSERT_EQUAL(timeTag, testCmdInfo.TimeTag);
    TEST_ASSERT_EQUAL(dataBlkPtr, testCmdInfo.DataBlkPtr_or_ModeWord);
    TEST_ASSERT_EQUAL(cmdWord, testCmdInfo.CMDWord);
    TEST_ASSERT_EQUAL(0, testCmdInfo.BUSA_or_BUSB);               // bit 29 of blockStatusWord
    TEST_ASSERT_EQUAL(0, testCmdInfo.CircBuff_rollover);          // bit 28 of blockStatusWord
    TEST_ASSERT_EQUAL(0, testCmdInfo.blk_err_stat);               // lower 16 bits of blockStatusWord
    TEST_ASSERT_EQUAL(8, testCmdInfo.RTaddr);                     // bits 15-11 of cmdWord
    TEST_ASSERT_EQUAL(0, testCmdInfo.T_or_R);                     // bit 10 of cmdWord
    TEST_ASSERT_EQUAL(0x19, testCmdInfo.SubAddr_or_ModeCMD);      // bits 9-5 of cmdWord
    TEST_ASSERT_EQUAL(0x01, testCmdInfo.DataLen_or_ModeCode);     // bits 4-0 of cmdWord
    TEST_ASSERT_EQUAL_HEX32(0x14, testInstance.CMDStack_ReadPtr); // 0x10 + 4

    TEST_ASSERT_EQUAL(4, result); // (0x20 - (0x10 + 4)) / 4 + 1 = 4
}

// Test case 5: Successful message read with wrap
void test_XRt1553B_GetCMDInfo_WhenMessageAvailableWithWrap_ShouldReturnMessageCount(void)
{
    // Arrange
    u32 cfg1_value = 0; // Not busy
    u32 stack_writePtr = 0x10; // Write pointer behind read pointer (wrap occurred)
    testInstance.CMDStack_ReadPtr = 0xF0; // 240 decimal

    u32 blockStatusWord = 0x20000000; // No SOM, with BUSA=0, rollover=1, error=0
    u32 timeTag = 0x11111111;
    u32 dataBlkPtr = 0x22222222;
    u32 cmdWord = 0x33333333;

    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, XRT53_STACKA_PTR_OFFSET, stack_writePtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0xF0, blockStatusWord);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0xF1, timeTag);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0xF2, dataBlkPtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0xF3, cmdWord);

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(8, result); // (0x10 + 256 - 0xF0) / 4 + 1 = (32/4) + 1 = 9
    TEST_ASSERT_EQUAL_HEX32(blockStatusWord, testCmdInfo.BlockStatusWord);
    TEST_ASSERT_EQUAL_HEX32(timeTag, testCmdInfo.TimeTag);
    TEST_ASSERT_EQUAL_HEX32(dataBlkPtr, testCmdInfo.DataBlkPtr_or_ModeWord);
    TEST_ASSERT_EQUAL_HEX32(cmdWord, testCmdInfo.CMDWord);
    TEST_ASSERT_EQUAL_HEX32(0xF4, testInstance.CMDStack_ReadPtr); // 0xF0 + 4
}

// Test case 6: Error bits in status word
void test_XRt1553B_GetCMDInfo_WhenErrorBitsPresent_ShouldCaptureErrorBits(void)
{
    // Arrange
    u32 cfg1_value = 0; // Not busy
    u32 stack_writePtr = 0x20;
    testInstance.CMDStack_ReadPtr = 0x10;

    u32 blockStatusWord = 0x5000ABCD; // BUSA=1, rollover=0, error=0xABCD
    u32 timeTag = 0x12345678;
    u32 dataBlkPtr = 0xABCDEF00;
    u32 cmdWord = 0x87654321;

    XRt1553B_ReadReg_ExpectAndReturn(testInstance.BaseAddress, XRT53_CFG1_OFFSET, cfg1_value);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, XRT53_STACKA_PTR_OFFSET, stack_writePtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x10, blockStatusWord);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x11, timeTag);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x12, dataBlkPtr);
    XRt1553B_ReadMem_ExpectAndReturn(testInstance.BaseAddress, 0x13, cmdWord);

    // Act
    u32 result = XRt1553B_GetCMDInfo(&testInstance, &testCmdInfo);

    // Assert
    TEST_ASSERT_EQUAL(4, result);
    TEST_ASSERT_EQUAL((XRT53_BLOCK_STATWORDS_ERR_MASK & blockStatusWord), testCmdInfo.blk_err_stat); // Lower 16 bits
}